/*
 * Copyright 2016-2019 yoara
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package yhao.infra.web.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import yhao.infra.apilist.JsonCommonCodeEnum;
import yhao.infra.apilist.JsonReturnCode;
import yhao.infra.apilist.ValidationForm;
import yhao.infra.common.util.CommonMapUtil;
import yhao.infra.web.common.security.encrypt.EncryptCheckResult;
import yhao.infra.web.common.security.encrypt.helper.RSAEncryptHelper;
import yhao.infra.web.common.util.CommonWebUtil;
import yhao.infra.web.common.validation.ValidationResult;
import yhao.infra.web.common.validation.pool.ValidationPoolBean;
import yhao.infra.web.json.MultipleClassPropertyPreFilter;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Controller 基类， 所有的controller 需要从此继承
 *
 * @author yoara
 */
public class BaseController {
    public static SerializerFeature[] features = {
            SerializerFeature.WriteMapNullValue,//输出值为null的字段
            SerializerFeature.WriteNullNumberAsZero, //数值字段如果为null,输出为0
            SerializerFeature.WriteNullStringAsEmpty, //字符类型字段如果为null,输出为""
            SerializerFeature.WriteNullListAsEmpty,//List字段如果为null,输出为[]
            SerializerFeature.WriteNullBooleanAsFalse,//Boolean字段如果为null,输出为false,而非null
            SerializerFeature.DisableCircularReferenceDetect};//禁止循环引用检测

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    protected ValidationPoolBean validationPoolBean;
    @Autowired
    protected RSAEncryptHelper rsaEncryptHelper;

    /**
     * 校验传递的参数是否符合要求，传递的Form须通过JSR-303标注
     *
     * @param param 待校验参数
     */
    protected ValidationResult validationParam(ValidationForm param) {
        return validationPoolBean.validationParam(param);
    }


    /**
     * 校验RSA参数加密，省事儿模式{@link #rsaCheck(String, String, boolean,ValidationForm)}
     * @return
     */
    protected EncryptCheckResult rsaCheck(ValidationForm form) {
        String encryptStr = getString(RSAEncryptHelper.RSA_PARAM_ENCRYPTSTR);
        boolean onlyMD5 = getBoolean(RSAEncryptHelper.RSA_PARAM_ONLYMD5, false);
        String key = getString(RSAEncryptHelper.RSA_PARAM_KEY);
        return rsaCheck(encryptStr, key, onlyMD5,form);
    }

    /**
     * 校验RSA参数加密
     *
     * @param encryptStr 前端加密返回的加密字符串
     * @param onlyMD5    是否仅用md5加密
     * @param key        私钥缓存key
     * @return
     */
    protected EncryptCheckResult rsaCheck(String encryptStr, String key,
                                          boolean onlyMD5,ValidationForm form) {
        if(form == null){
            return EncryptCheckResult.MATCHED;
        }
        //组装待验证参数串
        Map<String, String> paramMap = rsaEncryptHelper.makeCheckMap(getRequest(),form);
        if (paramMap == null) { //如果参数为空
            return EncryptCheckResult.EMPTY_ENCRYPTS;
        }
        if (encryptStr == null) { //如果加密字符串为空
            return EncryptCheckResult.EMPTY_ENCRYPTSTR;
        }
        if (key == null) { //如果key数为空
            return EncryptCheckResult.EMPTY_ENCRYPT_KEY;
        }
        return rsaEncryptHelper.rsaCheck(encryptStr, paramMap, key, onlyMD5);
    }

    public HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }

    public ServletContext getServletContext() {
        return ContextLoader.getCurrentWebApplicationContext().getServletContext();
    }

    public int getInt(String name) {
        return getInt(name, 0);
    }

    public int getInt(String name, int defaultValue) {
        return CommonWebUtil.getInt(name, defaultValue);
    }

    /**
     * 查询request中的参数
     **/
    private String getRequestParameter(String name) {
        HttpServletRequest request = getRequest();
        return request.getParameter(name);
    }


    public BigDecimal getBigDecimal(String name) {
        return getBigDecimal(name, null);
    }

    public BigDecimal getBigDecimal(String name, BigDecimal defaultValue) {
        return CommonWebUtil.getBigDecimal(name, defaultValue);
    }

    public String getString(String name) {
        return getString(name, null);
    }

    public String getString(String name, String defaultValue) {
        return CommonWebUtil.getString(name, defaultValue);
    }

    public Object outJson(HttpServletResponse response, String result) {
        try {
            response.setContentType("application/json;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            PrintWriter out = response.getWriter();
            out.print(result);
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return null;
    }

    public String[] getIpAddr(HttpServletRequest request) {
        return CommonWebUtil.getIpAddr(request);
    }

    public String redirect(HttpServletRequest request, HttpServletResponse response, String path, String ftlName) {
        try {
            response.sendRedirect(request.getContextPath() + path);
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return ftlName;
    }

    public String redirect(String path) {
        return "redirect:" + path;
    }

    public String getMACAddress(String ip) {
        return CommonWebUtil.getMACAddress(ip);
    }

    public Cookie getCookie(String cookieName) {
        return CommonWebUtil.getCookie(cookieName);
    }

    /**
     * 获取日期类型参数值
     *
     * @param name   参数名
     * @param format 日期格式
     * @return
     */
    public Date getDate(String name, String format) {
        return CommonWebUtil.getDate(name, format);
    }

    public double getDouble(String name) {
        return getDouble(name, 0);
    }

    public double getDouble(String name, double defaultValue) {
        return CommonWebUtil.getDouble(name, defaultValue);
    }

    /**
     * 如果name是1 就返回true,否则返回false
     *
     * @param name
     * @param defaultValue
     * @return
     */
    public Boolean getBoolean(String name, boolean defaultValue) {
        return CommonWebUtil.getBoolean(name, defaultValue);
    }


    /**
     * 返回成功信息不带结果集
     **/
    protected String successInfo() {
        return makeJsonStr(null, JsonCommonCodeEnum.C0000, null,null);
    }

    /**
     * 返回成功信息
     **/
    protected String successInfo(Object json) {
        return makeJsonStr(json, JsonCommonCodeEnum.C0000,null, null);
    }

    /**
     * 返回成功信息
     **/
    protected String successInfo(Object json, SerializeFilter filters) {
        return makeJsonStr(json, JsonCommonCodeEnum.C0000,null, filters);
    }

    /**
     * 返回成功信息，带时间格式
     **/
    protected String successInfo(Object json, String dateFormat) {
        return makeJsonStr(json, JsonCommonCodeEnum.C0000,dateFormat, null);
    }

    /**
     * 返回成功信息，带时间格式
     **/
    protected String successInfo(Object json, String dateFormat, SerializeFilter filters) {
        return makeJsonStr(json, JsonCommonCodeEnum.C0000,dateFormat, filters);
    }

    /**
     * 处理异常，返回出错信息
     **/
    protected String wrong(JsonReturnCode errCode) {
        Map<String, Object> result = new HashMap<>();
        result.put("status", errCode.getStatus());
        result.put("message", errCode.getMessage());
        result.put("result", null);
        return JSON.toJSONString(result);
    }

    /**
     * 使用自定义消息
     **/
    protected String withCustomMessage(String message, String code) {
        Map<String, Object> result = new HashMap<>();
        result.put("status", code);
        result.put("message", message);
        result.put("result", null);
        return JSON.toJSONString(result);
    }

    /**
     * 使用自定义消息
     **/
    protected String withCustomMessage(String message, JsonReturnCode code) {
        Map<String, Object> result = new HashMap<>();
        result.put("status", code.getStatus());
        result.put("message", StringUtils.isNotEmpty(message)?message:code.getMessage());
        result.put("result", null);
        return JSON.toJSONString(result);
    }

    /**
     * 处理成功，返回信息带过滤器过滤属性
     **/
    private String makeJsonStr(Object json,
                               JsonReturnCode code, String dateFormat, SerializeFilter... filters) {
        Map<String, Object> result = new HashMap<>();
        result.put("status", code.getStatus());
        result.put("message", code.getMessage());
        result.put("result", json);
        return JSON.toJSONString(result, SerializeConfig.globalInstance, filters,
                dateFormat, JSON.DEFAULT_GENERATE_FEATURE, features);
    }

    /**
     * 创建一维FastJson过滤filter
     * @return
     */
    protected SimplePropertyPreFilter makeSimpleFilter(Class clazz,String... property){
        return new SimplePropertyPreFilter(clazz,property);
    }

    /**
     * 创建多维FastJson过滤filter，包含所需字段
     * @param includeMap <属性类型.class,需要字段>
     * @return
     */
    protected MultipleClassPropertyPreFilter makeIncludeFilter(Map<Class,String[]> includeMap){
        if(CommonMapUtil.isEmpty(includeMap)){
            return null;
        }
        MultipleClassPropertyPreFilter filter = new MultipleClassPropertyPreFilter();
        for(Map.Entry<Class,String[]> entry:includeMap.entrySet()){
            filter.putInclude(entry.getKey(),entry.getValue());
        }
        return filter;
    }

    /**
     * 创建多维FastJson过滤filter，去除不需要的字段
     * @param excludeMap <属性类型.class,不需要字段>
     * @return
     */
    protected MultipleClassPropertyPreFilter makeExcludeFilter(Map<Class,String[]> excludeMap){
        if(CommonMapUtil.isEmpty(excludeMap)){
            return null;
        }
        MultipleClassPropertyPreFilter filter = new MultipleClassPropertyPreFilter();
        for(Map.Entry<Class,String[]> entry:excludeMap.entrySet()){
            filter.putExclude(entry.getKey(),entry.getValue());
        }
        return filter;
    }
}
